package fun.formoji.commons.handler;

import fun.formoji.commons.model.BusinessException;
import fun.formoji.commons.model.RestResponse;
import fun.formoji.commons.model.ServiceCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolationException;
import java.util.Objects;


/**
 * <code>ExceptionHandler</code>
 * <desc>
 * 描述：
 * <desc/>
 * <b>Creation Time:</b> 2020/9/10 14:25.
 *
 * @author hshe
 */
@RestControllerAdvice
@Slf4j
@Order(0)
public class GlobalExceptionHandler {
    /**
     * 校验异常处理. 400
     * 由Hibernate validate校验抛出
     * 校验Controller传入的BEAN参数
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public RestResponse<String> validateBeanExceptionHandler(MethodArgumentNotValidException e) {
        log.warn("Catch MethodArgumentNotValidException: {}", e.getMessage());
        String message = Objects.requireNonNull(e
                .getBindingResult()
                .getFieldError())
                .getDefaultMessage();
        return RestResponse.invalid(message, null);
    }

    /**
     * 校验异常处理. 400
     * 由Hibernate validate校验抛出
     * 校验Controller传入的BEAN参数
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(BindException.class)
    public RestResponse<String> validateBeanExceptionHandler(BindException e) {
        log.warn("Catch BindException: {}", e.getMessage());
        String message = Objects.requireNonNull(e.getBindingResult().getFieldError()).getDefaultMessage();
        return RestResponse.invalid(message, null);
    }

    /**
     * Controller参数校验异常处理. 400
     * 校验GET方法Controller传入的参数
     * 由Hibernate validate校验抛出
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(ConstraintViolationException.class)
    public RestResponse<String> validateGetParamsExceptionHandler(ConstraintViolationException e) {
        log.warn("Catch ConstraintViolationException: {}", e.getMessage(), e);
        String message = e
                .getConstraintViolations()
                .iterator()
                .next()
                .getMessage();
        return RestResponse.invalid(message, null);
    }


    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(value = IllegalArgumentException.class)
    public RestResponse<String> validParamsExceptionHandler(Exception e) {
        log.warn("Catch IllegalArgumentException Exception", e);
        return RestResponse.build(ServiceCode.PARAM_IS_INVALID, e.getMessage());
    }


    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(value = MissingServletRequestParameterException.class)
    public RestResponse<String> springRequestValid(Exception e) {
        log.warn("Catch MissingServletRequestParameterException",  e);
        return RestResponse.build(ServiceCode.PARAM_IS_INVALID, e.getMessage(), null);
    }


    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(value = HttpRequestMethodNotSupportedException.class)
    public RestResponse<String> httpMethodNotSupport(Exception e) {
        log.warn("Catch HttpRequestMethodNotSupportedException", e);
        return RestResponse.build(ServiceCode.PARAM_IS_INVALID, e.getMessage(), null);
    }


    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(value = BusinessException.class)
    public RestResponse<String> businessExceptionHandler(BusinessException e) {
        log.warn("Catch BusinessException", e);
        return RestResponse.build(e.getServiceCode(), e.getMessage(), null);
    }

    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(value = Exception.class)
    public RestResponse<Void> errorHandler(Exception e) {
        log.error("Catch Unknown Exception", e);
        return RestResponse.fail();
    }
}
